using System.Collections.Generic;
using System.Threading.Tasks;
using ZyGame.Transport.Common;
using ZyGame.Transport.TCP;
using ZyGame.Transport.UDP;
using ZyGame.Transport.Web;
using System;

namespace ZyGame.Transport
{
    public class NetManager : Singleton<NetManager>
    {
        private Dictionary<string, IChannel> channels = new Dictionary<string, IChannel>();

        public NetManager()
        {
            Client.Events.Register("APP_QUIT", () =>
            {
                foreach (var channel in channels)
                {
                    channel.Value.Close();
                }
            });
        }

        internal async Task<WebSocket> OnConnectWebSocket<T>(string name, string url, params IChannelHandler[] handlers) where T : INetworkSerialized
        {
            if (channels.TryGetValue(name, out IChannel channel))
            {
                return (WebSocket)channel;
            }

            channel = new WebSocket(url, Activator.CreateInstance<T>());
            channels.Add(name, channel);
            for (int i = 0; i < handlers.Length; i++)
            {
                channel.AddOutput(handlers[i]);
            }

            await channel.Connect();
            return (WebSocket)channel;
        }

        internal async Task<TCPChannel> OnConnectTcpSocket<T>(string name, string address, ushort port, params IChannelHandler[] handlers) where T : INetworkSerialized
        {
            if (!channels.TryGetValue(name, out IChannel channel))
            {
                channel = new TCPChannel(address, port, Activator.CreateInstance<T>());
                channels.Add(name, channel);
                for (int i = 0; i < handlers.Length; i++)
                {
                    channel.AddOutput(handlers[i]);
                }

                await channel.Connect();
            }

            return (TCPChannel)channel;
        }

        internal async Task<KCPChannel> OnConnectKcpSocket<T>(string name, int cid, string address, ushort port, params IChannelHandler[] handlers) where T : INetworkSerialized
        {
            if (!channels.TryGetValue(name, out IChannel channel))
            {
                channel = new KCPChannel(cid, address, port, Activator.CreateInstance<T>());
                channels.Add(name, channel);
                for (int i = 0; i < handlers.Length; i++)
                {
                    channel.AddOutput(handlers[i]);
                }

                await channel.Connect();
            }

            return (KCPChannel)channel;
        }

        internal async Task CloseConnect(string name)
        {
            if (channels.TryGetValue(name, out IChannel channel))
            {
                await channel.Close();
                channels.Remove(name);
            }
        }

        public IChannel GetChannel(string name)
        {
            if (channels.TryGetValue(name, out IChannel channel))
            {
                return channel;
            }

            return default;
        }
    }
}